from flask import Blueprint, request
from flask_jwt_extended import jwt_required, get_jwt_identity
from app import db
from app.models import Leaderboard, User
from app.utils.response import success_response, error_response, paginated_response
from app.utils.decorators import admin_required
from loguru import logger

leaderboards_bp = Blueprint('leaderboards', __name__)

@leaderboards_bp.route('/', methods=['GET'])
def get_leaderboard():
    """获取排行榜"""
    try:
        period_type = request.args.get("period_type") or request.args.get("type", "all_time")
        # 参数映射
        type_mapping = {"total": "all_time", "month": "monthly", "week": "weekly"}
        if period_type in type_mapping:
            period_type = type_mapping[period_type]
        page = request.args.get('page', 1, type=int)
        per_page = min(request.args.get('per_page', 20, type=int), 100)
        
        # 验证周期类型
        valid_periods = ['daily', 'weekly', 'monthly', 'all_time']
        if period_type not in valid_periods:
            return error_response('无效的周期类型', 400)
        
        # 获取排行榜数据
        pagination = Leaderboard.get_leaderboard(period_type, page, per_page)
        
        # 构建返回数据
        leaderboard_data = []
        for record in pagination.items:
            record_dict = record.to_dict()
            # 添加用户信息
            record_dict['user'] = record.user.to_dict()
            leaderboard_data.append(record_dict)
        
        return paginated_response(
            leaderboard_data,
            page,
            per_page,
            pagination.total,
            f'{period_type}排行榜'
        )
        
    except Exception as e:
        logger.error(f"获取排行榜失败: {e}")
        return error_response('获取排行榜失败', 500)

@leaderboards_bp.route('/admin/', methods=['GET'])
@admin_required
def admin_leaderboard_list():
    """管理员获取排行榜分页列表"""
    try:
        period_type = request.args.get("period_type") or request.args.get("type", "all_time")
        # 参数映射
        type_mapping = {"total": "all_time", "month": "monthly", "week": "weekly"}
        if period_type in type_mapping:
            period_type = type_mapping[period_type]
        page = request.args.get('page', 1, type=int)
        per_page = min(request.args.get('per_page', 20, type=int), 100)
        valid_periods = ['daily', 'weekly', 'monthly', 'all_time']
        if period_type not in valid_periods:
            return error_response('无效的周期类型', 400)
        pagination = Leaderboard.get_leaderboard(period_type, page, per_page)
        leaderboard_data = []
        for record in pagination.items:
            record_dict = record.to_dict()
            record_dict['user'] = record.user.to_dict() if hasattr(record, 'user') and record.user else None
            leaderboard_data.append(record_dict)
        return paginated_response(
            leaderboard_data,
            page,
            per_page,
            pagination.total,
            f'{period_type}排行榜'
        )
    except Exception as e:
        logger.error(f"管理员获取排行榜分页失败: {e}")
        return error_response('获取排行榜分页失败', 500)

@leaderboards_bp.route('/my-rank', methods=['GET'])
@jwt_required()
def get_my_rank():
    """获取我的排名"""
    try:
        current_user_id = get_jwt_identity()
        period_type = request.args.get("period_type") or request.args.get("type", "all_time")
        # 参数映射
        type_mapping = {"total": "all_time", "month": "monthly", "week": "weekly"}
        if period_type in type_mapping:
            period_type = type_mapping[period_type]
        
        # 验证周期类型
        valid_periods = ['daily', 'weekly', 'monthly', 'all_time']
        if period_type not in valid_periods:
            return error_response('无效的周期类型', 400)
        
        # 获取用户排名
        from datetime import datetime, timedelta
        today = datetime.now().date()
        
        if period_type == 'daily':
            period_date = today
        elif period_type == 'weekly':
            period_date = today - timedelta(days=today.weekday())
        elif period_type == 'monthly':
            period_date = today.replace(day=1)
        else:  # all_time
            period_date = today
        
        leaderboard_record = Leaderboard.query.filter_by(
            user_id=current_user_id,
            period_type=period_type,
            period_date=period_date
        ).first()
        
        if not leaderboard_record:
            return success_response({
                'rank_position': 0,
                'total_score': 0,
                'exam_count': 0,
                'pass_count': 0,
                'avg_score': 0,
                'period_type': period_type
            })
        
        return success_response({
            'rank_position': leaderboard_record.rank_position,
            'total_score': leaderboard_record.total_score,
            'exam_count': leaderboard_record.exam_count,
            'pass_count': leaderboard_record.pass_count,
            'avg_score': float(leaderboard_record.avg_score),
            'period_type': period_type
        })
        
    except Exception as e:
        logger.error(f"获取我的排名失败: {e}")
        return error_response('获取排名失败', 500)

@leaderboards_bp.route('/update', methods=['POST'])
@jwt_required()
def update_my_stats():
    """更新我的统计数据"""
    try:
        current_user_id = get_jwt_identity()
        period_type = request.args.get("period_type") or request.args.get("type", "all_time")
        # 参数映射
        type_mapping = {"total": "all_time", "month": "monthly", "week": "weekly"}
        if period_type in type_mapping:
            period_type = type_mapping[period_type]
        
        # 验证周期类型
        valid_periods = ['daily', 'weekly', 'monthly', 'all_time']
        if period_type not in valid_periods:
            return error_response('无效的周期类型', 400)
        
        # 更新统计数据
        leaderboard_record = Leaderboard.update_user_stats(current_user_id, period_type)
        
        return success_response(leaderboard_record.to_dict(), '统计数据更新成功')
        
    except Exception as e:
        logger.error(f"更新统计数据失败: {e}")
        return error_response('更新统计数据失败', 500)

# 管理员接口
@leaderboards_bp.route('/admin/stats', methods=['GET'])
@admin_required
def admin_get_stats():
    """管理员获取统计信息"""
    try:
        period_type = request.args.get("period_type") or request.args.get("type", "all_time")
        # 参数映射
        type_mapping = {"total": "all_time", "month": "monthly", "week": "weekly"}
        if period_type in type_mapping:
            period_type = type_mapping[period_type]
        
        # 验证周期类型
        valid_periods = ['daily', 'weekly', 'monthly', 'all_time']
        if period_type not in valid_periods:
            return error_response('无效的周期类型', 400)
        
        # 获取统计信息
        from datetime import datetime, timedelta
        today = datetime.now().date()
        
        if period_type == 'daily':
            period_date = today
        elif period_type == 'weekly':
            period_date = today - timedelta(days=today.weekday())
        elif period_type == 'monthly':
            period_date = today.replace(day=1)
        else:  # all_time
            period_date = today
        
        # 统计总数
        total_users = Leaderboard.query.filter_by(
            period_type=period_type,
            period_date=period_date
        ).count()
        
        # 统计总分数
        total_score_result = db.session.query(db.func.sum(Leaderboard.total_score)).filter_by(
            period_type=period_type,
            period_date=period_date
        ).scalar()
        total_score = total_score_result or 0
        
        # 统计平均分
        avg_score_result = db.session.query(db.func.avg(Leaderboard.avg_score)).filter_by(
            period_type=period_type,
            period_date=period_date
        ).scalar()
        avg_score = float(avg_score_result) if avg_score_result else 0
        
        # 统计考试次数
        total_exams_result = db.session.query(db.func.sum(Leaderboard.exam_count)).filter_by(
            period_type=period_type,
            period_date=period_date
        ).scalar()
        total_exams = total_exams_result or 0
        
        # 统计通过次数
        total_passes_result = db.session.query(db.func.sum(Leaderboard.pass_count)).filter_by(
            period_type=period_type,
            period_date=period_date
        ).scalar()
        total_passes = total_passes_result or 0
        
        stats = {
            'period_type': period_type,
            'period_date': period_date.isoformat(),
            'total_users': total_users,
            'total_score': total_score,
            'avg_score': avg_score,
            'total_exams': total_exams,
            'total_passes': total_passes,
            'pass_rate': (total_passes / total_exams * 100) if total_exams > 0 else 0
        }
        
        return success_response(stats)
        
    except Exception as e:
        logger.error(f"获取统计信息失败: {e}")
        return error_response('获取统计信息失败', 500)

@leaderboards_bp.route('/admin/update-all', methods=['POST'])
@admin_required
def admin_update_all_stats():
    """管理员更新所有用户统计数据"""
    try:
        period_type = request.args.get("period_type") or request.args.get("type", "all_time")
        # 参数映射
        type_mapping = {"total": "all_time", "month": "monthly", "week": "weekly"}
        if period_type in type_mapping:
            period_type = type_mapping[period_type]
        
        # 验证周期类型
        valid_periods = ['daily', 'weekly', 'monthly', 'all_time']
        if period_type not in valid_periods:
            return error_response('无效的周期类型', 400)
        
        # 获取所有用户
        users = User.query.all()
        updated_count = 0
        
        for user in users:
            try:
                Leaderboard.update_user_stats(user.id, period_type)
                updated_count += 1
            except Exception as e:
                logger.error(f"更新用户 {user.id} 统计数据失败: {e}")
                continue
        
        return success_response({
            'updated_count': updated_count,
            'total_users': len(users),
            'period_type': period_type
        }, f'成功更新 {updated_count} 个用户的统计数据')
        
    except Exception as e:
        logger.error(f"更新所有用户统计数据失败: {e}")
        return error_response('更新统计数据失败', 500)

@leaderboards_bp.route('/admin/export', methods=['GET'])
@admin_required
def admin_export_leaderboard():
    """管理员导出排行榜数据"""
    try:
        period_type = request.args.get("period_type") or request.args.get("type", "all_time")
        # 参数映射
        type_mapping = {"total": "all_time", "month": "monthly", "week": "weekly"}
        if period_type in type_mapping:
            period_type = type_mapping[period_type]
        
        # 验证周期类型
        valid_periods = ['daily', 'weekly', 'monthly', 'all_time']
        if period_type not in valid_periods:
            return error_response('无效的周期类型', 400)
        
        # 获取排行榜数据
        from datetime import datetime, timedelta
        today = datetime.now().date()
        
        if period_type == 'daily':
            period_date = today
        elif period_type == 'weekly':
            period_date = today - timedelta(days=today.weekday())
        elif period_type == 'monthly':
            period_date = today.replace(day=1)
        else:  # all_time
            period_date = today
        
        records = Leaderboard.query.filter_by(
            period_type=period_type,
            period_date=period_date
        ).order_by(Leaderboard.rank_position.asc()).all()
        
        # 构建导出数据
        export_data = []
        for record in records:
            export_data.append({
                'rank': record.rank_position,
                'user_id': record.user_id,
                'nickname': record.user.nickname or '未知用户',
                'total_score': record.total_score,
                'exam_count': record.exam_count,
                'pass_count': record.pass_count,
                'avg_score': float(record.avg_score),
                'pass_rate': (record.pass_count / record.exam_count * 100) if record.exam_count > 0 else 0
            })
        
        return success_response({
            'period_type': period_type,
            'period_date': period_date.isoformat(),
            'total_records': len(export_data),
            'data': export_data
        })
        
    except Exception as e:
        logger.error(f"导出排行榜数据失败: {e}")
        return error_response('导出数据失败', 500) 
# 小程序兼容接口
@leaderboards_bp.route('/list', methods=['GET'])
def get_leaderboard_for_miniprogram():
    """获取排行榜（小程序兼容）"""
    try:
        # 处理小程序的参数映射
        type_param = request.args.get('type', 'total')
        page = request.args.get('page', 1, type=int)
        per_page = min(request.args.get('per_page', 20, type=int), 100)
        
        # 参数映射
        type_mapping = {
            'total': 'all_time',
            'month': 'monthly',
            'week': 'weekly'
        }
        
        period_type = type_mapping.get(type_param, 'all_time')
        
        # 获取排行榜数据
        pagination = Leaderboard.get_leaderboard(period_type, page, per_page)
        
        # 构建返回数据
        leaderboard_data = []
        for record in pagination.items:
            record_dict = record.to_dict()
            # 添加用户信息
            record_dict['user'] = record.user.to_dict()
            leaderboard_data.append(record_dict)
        
        # 获取当前用户排名（如果已登录）
        current_user_id = None
        my_rank = None
        
        try:
            from flask_jwt_extended import get_jwt_identity
            current_user_id = get_jwt_identity()
            if current_user_id:
                from datetime import datetime, timedelta
                today = datetime.now().date()
                
                if period_type == 'daily':
                    period_date = today
                elif period_type == 'weekly':
                    period_date = today - timedelta(days=today.weekday())
                elif period_type == 'monthly':
                    period_date = today.replace(day=1)
                else:  # all_time
                    period_date = today
                
                leaderboard_record = Leaderboard.query.filter_by(
                    user_id=current_user_id,
                    period_type=period_type,
                    period_date=period_date
                ).first()
                
                if leaderboard_record:
                    my_rank = {
                        'rank_position': leaderboard_record.rank_position,
                        'total_score': leaderboard_record.total_score,
                        'exam_count': leaderboard_record.exam_count,
                        'pass_count': leaderboard_record.pass_count,
                        'avg_score': float(leaderboard_record.avg_score)
                    }
        except:
            pass  # 忽略JWT错误，允许未登录用户查看排行榜
        
        return success_response({
            'items': leaderboard_data,
            'page': page,
            'per_page': per_page,
            'total': pagination.total,
            'my_rank': my_rank
        })
        
    except Exception as e:
        logger.error(f"获取排行榜失败: {e}")
        return error_response('获取排行榜失败', 500)
